#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "mqttManager.h"
#include "settingsManager.h"
#include "logger.h"
#include "Settings.h"





int  mqtt_connect(T_MQTT_MANAGER* manager, const char *host, int port, const char * username, const char *password, int keepalive){
    if((NULL == manager) || (NULL == manager->mosq)) {
        return MOSQ_ERR_INVAL;
    }
    if((NULL != username) && (0 < strlen(username))){
        int ret = mosquitto_username_pw_set(manager->mosq, username, password);
        if(MOSQ_ERR_SUCCESS != ret){
            return ret;
        }
    }
    int ret = mosquitto_connect(manager->mosq, host, port, keepalive);
    log_i("host: %s;port:%d;keepalive:%d;ret:%d", host, port, keepalive, ret);
    return ret;
}

int  mqtt_subscribe(T_MQTT_MANAGER* manager, const char *topic, int qos){
    if((NULL == manager) || (NULL == manager->mosq)) {
        return MOSQ_ERR_INVAL;
    }
    if((NULL != topic) && (0 < strlen(topic)) && (NULL != manager->mosq)){
        return mosquitto_subscribe(manager->mosq, NULL, topic, qos);
    }else{
        return MOSQ_ERR_INVAL;
    }
}

int  mqtt_subscribe_multi(T_MQTT_MANAGER* manager, char* topics[], int count, int qos){
    if((NULL == manager) || (NULL == topics[0]) || (1 > strlen(topics[0])) || (1 > count)){
        return MOSQ_ERR_INVAL;
    }
    int ret = MOSQ_ERR_SUCCESS;
    for(int i = 0; i < count; i++){
        if((NULL == topics[i]) || (1 > strlen(topics[i]))){
            int r = mqtt_subscribe(manager, topics[i], qos);
            if(MOSQ_ERR_SUCCESS != r){
                log_w("subscribe topic: {%s} failed", topics[i]);
                ret = r;
            }
        }
    }
    return ret;
}

int  mqtt_publish(T_MQTT_MANAGER* manager, const char *topic, int data_len, const void *data, int qos, bool retain){
    if((NULL == manager) || (NULL == manager->mosq) || (NULL == topic) || (1 > data_len) || (NULL == data) || (1 > strlen(topic))){
        return MOSQ_ERR_INVAL;
    }
    return mosquitto_publish(manager->mosq, NULL, topic, data_len, data, qos, retain);
}

int  mqtt_start(T_MQTT_MANAGER* manager){
    // 启动MQTT循环
    if((NULL == manager) || (NULL == manager->mosq)){
        return MOSQ_ERR_INVAL;
    }
    
    return mosquitto_loop_start(manager->mosq);
}
int mqtt_destroy(T_MQTT_MANAGER* manager){
    if((NULL == manager) || (NULL == manager->mosq)){
        return MOSQ_ERR_SUCCESS;
    }
    mosquitto_destroy(manager->mosq);
    int ret = mosquitto_lib_cleanup();
    return ret;

}
int  mqtt_stop(T_MQTT_MANAGER* manager){
    if((NULL == manager) || (NULL == manager->mosq)){
        return MOSQ_ERR_SUCCESS;
    }
    int ret = mosquitto_disconnect(manager->mosq);
    if(MOSQ_ERR_SUCCESS == ret){
        ret = mosquitto_loop_stop(manager->mosq, false);
    }
    return mqtt_destroy(manager);
}

void mqtt_callbackFunc(T_MQTT_MANAGER* manager, T_CALLBACK_TYPE cbType, void *data, int data_len, int result, void *arg){
    if((NULL == manager) || (NULL == manager->callbacks)){
        return ;
    }
    T_MQTT_CALLBACK* cb = manager->callbacks;
    T_MQTT_FUNCTION_CALLBACK func = cb->func_cb;
    while(NULL != func){
        func(cbType, data, data_len, result, arg);
        cb = cb->next;
        if(NULL == cb){
            break;
        }
        func = cb->func_cb;
    }

}

void mqtt_on_connect(struct mosquitto *mosq, void *obj, int rc){
    if((NULL == mosq) || (NULL == obj)){
        return ;
    }
    mqtt_callbackFunc((T_MQTT_MANAGER*)obj, CALLBACK_TYPE_CONNECTED, NULL, 0, rc, obj);
}

void mqtt_on_disconnect(struct mosquitto *mosq, void *obj, int rc){
   if((NULL == mosq) || (NULL == obj)){
        return ;
    }
    mqtt_callbackFunc((T_MQTT_MANAGER*)obj, CALLBACK_TYPE_DISCONNECTED, NULL, 0, rc, obj);
}

void mqtt_on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message){
    if((NULL == mosq) || (NULL == obj) || (NULL == message)){
        return ;
    }
    mqtt_callbackFunc((T_MQTT_MANAGER*)obj, CALLBACK_TYPE_MESSAGE, (void *)message, message->payloadlen, 0, obj);
}

void mqtt_on_publish(struct mosquitto *mosq, void *obj, int mid){
   if((NULL == mosq) || (NULL == obj)){
        return ;
    }
    mqtt_callbackFunc((T_MQTT_MANAGER*)obj, CALLBACK_TYPE_PUBLISH, NULL, 0, mid, obj);
}

void mqtt_on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos){
   if((NULL == mosq) || (NULL == obj)){
        return ;
    }
    mqtt_callbackFunc((T_MQTT_MANAGER*)obj, CALLBACK_TYPE_SUBSCRIBE, NULL, 0, mid, obj);
}

void mqtt_on_unsubscribe(struct mosquitto *mosq, void *obj, int mid){
    if((NULL == mosq) || (NULL == obj)){
        return ;
    } 
    mqtt_callbackFunc((T_MQTT_MANAGER*)obj, CALLBACK_TYPE_UNSUBSCRIBE, NULL, 0, mid, obj);
}

void mqtt_on_log(struct mosquitto *mosq, void *obj, int level, const char *str){
    if((NULL == mosq) || (NULL == obj)){
        return ;
    }
    mqtt_callbackFunc((T_MQTT_MANAGER*)obj, CALLBACK_TYPE_LOG, (void *)str, strlen(str), 0, obj);
}

void mqtt_setCallback(T_MQTT_MANAGER* manager){
    if(NULL == manager){
        return ;
    }
    mosquitto_connect_callback_set(manager->mosq,     mqtt_on_connect);
    mosquitto_disconnect_callback_set(manager->mosq,  mqtt_on_disconnect);
    mosquitto_publish_callback_set(manager->mosq,     mqtt_on_publish);
    mosquitto_message_callback_set(manager->mosq,     mqtt_on_message);
    mosquitto_subscribe_callback_set(manager->mosq,   mqtt_on_subscribe);
    mosquitto_unsubscribe_callback_set(manager->mosq, mqtt_on_unsubscribe);
    mosquitto_log_callback_set(manager->mosq,         mqtt_on_log);
}

int mqtt_set_will(T_MQTT_MANAGER* manager, const char *topic, int payloadlen, const void *payload, int qos, bool retain){
    if((NULL == manager) || (NULL == manager->mosq)){
        return MOSQ_ERR_INVAL;
    }
    return mosquitto_will_set(manager->mosq, topic, payloadlen, payload, qos, retain);
}

int mqtt_init(T_MQTT_MANAGER* manager){
    if(NULL == manager){
        return MOSQ_ERR_INVAL;
    }
    int ret = mosquitto_lib_init();
    if(MOSQ_ERR_SUCCESS == ret){
        manager->mosq = mosquitto_new(NULL, true, manager);
        if(NULL == manager->mosq){
            log_e("create MQTT client failed: %s", strerror(errno));
            return errno;
        }else{
            mqtt_setCallback(manager);
        }
    }
    return ret;
}